/*globals Markdown, requirejs */
define([
        "jquery",
        "underscore",
        "crel",
        "editor",
        "layout",
        "constants",
        "utils",
        "storage",
        "settings",
        "eventMgr",
        "text!html/bodyEditor.html",
        "text!html/bodyViewer.html",
        "text!html/tooltipSettingsTemplate.html",
        "text!html/tooltipSettingsPdfOptions.html",
        'pagedown'
        ], function($, _, crel, editor, layout, constants, utils, storage, settings, eventMgr, bodyEditorHTML, bodyViewerHTML, settingsTemplateTooltipHTML, settingsPdfOptionsTooltipHTML) {


            var core = {};

            // Used for periodic tasks
            var intervalId;

            // Used to detect user activity
            var isUserReal = false;
            var userActive = false;
            var windowUnique = true;
            var userLastActivity = 0;

            function setUserActive() {
                isUserReal = true;
                userActive = true;
                var currentTime = utils.currentTime;
                if(currentTime > userLastActivity + 1000) {
                    userLastActivity = currentTime;
                    eventMgr.onUserActive();
                }
            }

            function isUserActive() {
                if(utils.currentTime - userLastActivity > constants.USER_IDLE_THRESHOLD) {
                    userActive = false;
                }
                return userActive && windowUnique;
            }

            // Used to only have 1 window of the application in the same browser
            var windowId;

            function checkWindowUnique() {
                if(isUserReal === false || windowUnique === false) {
                    return;
                }
                if(windowId === undefined) {
                    windowId = utils.randomString();
                    storage.frontWindowId = windowId;
                }
                var frontWindowId = storage.frontWindowId;
                if(frontWindowId != windowId) {
                    windowUnique = false;
                    if(intervalId !== undefined) {
                        clearInterval(intervalId);
                    }
                    $(".modal").modal("hide");
                    $('.modal-non-unique').modal("show");
                    // Attempt to close the window
                    window.close();
                }
            }

            // Offline management
            var isOffline = false;
            var offlineTime = utils.currentTime;
            core.setOffline = function() {
                offlineTime = utils.currentTime;
                if(isOffline === false) {
                    isOffline = true;
                    eventMgr.onOfflineChanged(true);
                }
            };
            function setOnline() {
                if(isOffline === true) {
                    isOffline = false;
                    eventMgr.onOfflineChanged(false);
                }
            }

            function checkOnline() {
                // Try to reconnect if we are offline but we have some network
                if(isOffline === true && navigator.onLine === true && offlineTime + constants.CHECK_ONLINE_PERIOD < utils.currentTime) {
                    offlineTime = utils.currentTime;
                    // Try to download anything to test the connection
                    /*$.ajax({
                        url: "//www.google.com/jsapi",
                        timeout: constants.AJAX_TIMEOUT,
                        dataType: "script"
                    }).done(function() {
                        setOnline();
                    });*/
                }
            }

            // Load settings in settings dialog
            var $themeInputElt;

            function loadSettings() {

                // Layout orientation
                utils.setInputRadio("radio-layout-orientation", settings.layoutOrientation);
                // Theme
                utils.setInputValue($themeInputElt, window.theme);
                $themeInputElt.change();
                // Lazy rendering
                utils.setInputChecked("#input-settings-lazy-rendering", settings.lazyRendering);
                // Editor font class
                utils.setInputRadio("radio-settings-editor-font-class", settings.editorFontClass);
                // Font size ratio
                utils.setInputValue("#input-settings-font-size", settings.fontSizeRatio);
                // Max width ratio
                utils.setInputValue("#input-settings-max-width", settings.maxWidthRatio);
                // Cursor locking ratio
                utils.setInputValue("#input-settings-cursor-focus", settings.cursorFocusRatio);
                // Default content
                utils.setInputValue("#textarea-settings-default-content", settings.defaultContent);
                // Edit mode
                utils.setInputRadio("radio-settings-edit-mode", settings.editMode);
                // Commit message
                utils.setInputValue("#input-settings-publish-commit-msg", settings.commitMsg);
                // Markdown MIME type
                utils.setInputValue("#input-settings-markdown-mime-type", settings.markdownMimeType);
                // Gdrive multi-accounts
                utils.setInputValue("#input-settings-gdrive-multiaccount", settings.gdriveMultiAccount);
                // Gdrive full access
                utils.setInputChecked("#input-settings-gdrive-full-access", settings.gdriveFullAccess);
                // Dropbox full access
                utils.setInputChecked("#input-settings-dropbox-full-access", settings.dropboxFullAccess);
                // GitHub full access
                utils.setInputChecked("#input-settings-github-full-access", settings.githubFullAccess);
                // Template
                utils.setInputValue("#textarea-settings-publish-template", settings.template);
                // PDF template
                utils.setInputValue("#textarea-settings-pdf-template", settings.pdfTemplate);
                // PDF options
                utils.setInputValue("#textarea-settings-pdf-options", settings.pdfOptions);

                // Load extension settings
                eventMgr.onLoadSettings();
            }

            // Save settings from settings dialog
            function saveSettings(event) {
                var newSettings = {};

                // Layout orientation
                newSettings.layoutOrientation = utils.getInputRadio("radio-layout-orientation");
                // Theme
                var theme = utils.getInputValue($themeInputElt);
                // Lazy Rendering
                newSettings.lazyRendering = utils.getInputChecked("#input-settings-lazy-rendering");
                // Editor font class
                newSettings.editorFontClass = utils.getInputRadio("radio-settings-editor-font-class");
                // Font size ratio
                newSettings.fontSizeRatio = utils.getInputFloatValue("#input-settings-font-size", event, 0.1, 10);
                // Max width ratio
                newSettings.maxWidthRatio = utils.getInputFloatValue("#input-settings-max-width", event, 0.1, 10);
                // Cursor locking ratio
                newSettings.cursorFocusRatio = utils.getInputFloatValue("#input-settings-cursor-focus", event, 0, 1);
                // Default content
                newSettings.defaultContent = utils.getInputValue("#textarea-settings-default-content");
                // Edit mode
                newSettings.editMode = utils.getInputRadio("radio-settings-edit-mode");
                // Commit message
                newSettings.commitMsg = utils.getInputTextValue("#input-settings-publish-commit-msg", event);
                // Gdrive multi-accounts
                newSettings.gdriveMultiAccount = utils.getInputIntValue("#input-settings-gdrive-multiaccount");
                // Markdown MIME type
                newSettings.markdownMimeType = utils.getInputValue("#input-settings-markdown-mime-type");
                // Gdrive full access
                newSettings.gdriveFullAccess = utils.getInputChecked("#input-settings-gdrive-full-access");
                // Drobox full access
                newSettings.dropboxFullAccess = utils.getInputChecked("#input-settings-dropbox-full-access");
                // GitHub full access
                newSettings.githubFullAccess = utils.getInputChecked("#input-settings-github-full-access");
                // Template
                newSettings.template = utils.getInputTextValue("#textarea-settings-publish-template", event);
                // PDF template
                newSettings.pdfTemplate = utils.getInputTextValue("#textarea-settings-pdf-template", event);
                // PDF options
                newSettings.pdfOptions = utils.getInputJSONValue("#textarea-settings-pdf-options", event);

                // Save extension settings
                newSettings.extensionSettings = {};
                eventMgr.onSaveSettings(newSettings.extensionSettings, event);

                if(!event.isPropagationStopped()) {
                    if(settings.dropboxFullAccess !== newSettings.dropboxFullAccess) {
                        storage.removeItem('dropbox.lastChangeId');
                    }
                    $.extend(settings, newSettings);
                    storage.settings = JSON.stringify(settings);
                    storage.themeV4 = theme;
                }
            }

            // Create the PageDown editor
            var pagedownEditor;
            var fileDesc;
            core.initEditor = function(fileDescParam) {
                if(fileDesc !== undefined) {
                    eventMgr.onFileClosed(fileDesc);
                }
                //fileDesc = fileDescParam;

                if(pagedownEditor !== undefined) {
                    // If the editor is already created
                    editor.undoMgr.init();
                    return pagedownEditor.uiManager.setUndoRedoButtonStates();
                }

                // Create the converter and the editor
                var converter = new Markdown.Converter();
                var options = {
                    _DoItalicsAndBold: function(text) {
                        // Restore original markdown implementation
                        text = text.replace(/(\*\*|__)(?=\S)(.+?[*_]*)(?=\S)\1/g,
                                "<strong>$2</strong>");
                        text = text.replace(/(\*|_)(?=\S)(.+?)(?=\S)\1/g,
                                "<em>$2</em>");
                        return text;
                    }
                };
                converter.setOptions(options);
                pagedownEditor = new Markdown.Editor(converter, undefined, {
                    undoManager: editor.undoMgr
                });

                // Custom insert link dialog
                pagedownEditor.hooks.set("insertLinkDialog", function(callback) {
                    core.insertLinkCallback = callback;
                    utils.resetModalInputs();
                    $(".modal-insert-link").modal();
                    return true;
                });
                // Custom insert image dialog
                pagedownEditor.hooks.set("insertImageDialog", function(callback) {
                    core.insertLinkCallback = callback;
                    if(core.catchModal) {
                        return true;
                    }
                    utils.resetModalInputs();
                    $(".modal-insert-image").modal();
                    return true;
                });

                eventMgr.onPagedownConfigure(pagedownEditor);
                pagedownEditor.hooks.chain("onPreviewRefresh", eventMgr.onAsyncPreview);
                pagedownEditor.run();
                editor.undoMgr.init();

                // Hide default buttons
                $(".wmd-button-row li").addClass("btn btn-success").css("left", 0).find("span").hide();

                // Add customized buttons
                var $btnGroupElt = $('.wmd-button-group1');
                $("#wmd-bold-button").append($('<i class="icon-bold">')).appendTo($btnGroupElt);
                $("#wmd-italic-button").append($('<i class="icon-italic">')).appendTo($btnGroupElt);
                $btnGroupElt = $('.wmd-button-group2');
                $("#wmd-link-button").append($('<i class="icon-globe">')).appendTo($btnGroupElt);
                $("#wmd-quote-button").append($('<i class="icon-indent-right">')).appendTo($btnGroupElt);
                $("#wmd-code-button").append($('<i class="icon-code">')).appendTo($btnGroupElt);
                $("#wmd-image-button").append($('<i class="icon-picture">')).appendTo($btnGroupElt);
                $btnGroupElt = $('.wmd-button-group3');
                $("#wmd-olist-button").append($('<i class="icon-list-numbered">')).appendTo($btnGroupElt);
                $("#wmd-ulist-button").append($('<i class="icon-list-bullet">')).appendTo($btnGroupElt);
                $("#wmd-heading-button").append($('<i class="icon-text-height">')).appendTo($btnGroupElt);
                $("#wmd-hr-button").append($('<i class="icon-ellipsis">')).appendTo($btnGroupElt);
                $btnGroupElt = $('.wmd-button-group5');
                $("#wmd-undo-button").append($('<i class="icon-reply">')).appendTo($btnGroupElt);
                $("#wmd-redo-button").append($('<i class="icon-forward">')).appendTo($btnGroupElt);
            };

            // Initialize multiple things and then fire eventMgr.onReady
            core.onReady = function() {
                // Add RTL class
                document.body.className += ' ' + settings.editMode;

                if(window.viewerMode === true) {
                    document.body.innerHTML = bodyViewerHTML;
                }
                else {
                    document.body.innerHTML = bodyEditorHTML;
                }

                // Initialize utils library
                utils.init();

                // listen to online/offline events
                $(window).on('offline', core.setOffline);
                $(window).on('online', setOnline);
                if(navigator.onLine === false) {
                    core.setOffline();
                }

                // Detect user activity
                $(document).mousemove(setUserActive).keypress(setUserActive);

                layout.init();
                editor.init();

                // Do periodic tasks
                intervalId = window.setInterval(function() {
                    utils.updateCurrentTime();
                    //checkWindowUnique();
                    if(isUserActive() === true || window.viewerMode === true) {
                        eventMgr.onPeriodicRun();
                        checkOnline();
                    }
                }, 1000);

                eventMgr.onReady();
            };

            var appId = 'ESTHdCYOi18iLhhO';
            //var monetize = new MonetizeJS({
                //applicationID: appId
            //});
            var $alerts = $();

            function isSponsor(payments) {
                var result = payments && payments.app == appId && (
                        (payments.chargeOption && payments.chargeOption.alias == 'once') ||
                        (payments.subscriptionOption && payments.subscriptionOption.alias == 'yearly'));
                eventMgr.isSponsor = result;
                return result;
            }

            function removeAlerts() {
                $alerts.remove();
                $alerts = $();
            }

            function performPayment() {
                //monetize.getPayments({
                    //pricingOptions: [
                    //'once',
                    //'yearly'
                    //]
                //}, function(err, payments) {
                    //if(isSponsor(payments)) {
                        //eventMgr.onMessage('Thank you for sponsoring StackEdit!');
                        //removeAlerts();
                    //}
                //});
            }

            var checkPayment = _.debounce(function() {
                if(isOffline) {
                    return;
                }
                //monetize.getPaymentsImmediate(function(err, payments) {
                    //removeAlerts();
                    //if(!isSponsor(payments)) {
                        //_.each(document.querySelectorAll('.modal-body'), function(modalBodyElt) {
                            //var $elt = $('<div class="alert alert-danger">Please consider <a href="#">sponsoring StackEdit</a> for $5/year (or <a href="#">sign in</a> if you\'re already a sponsor).</div>');
                            //$elt.find('a').click(performPayment);
                            //modalBodyElt.insertBefore($elt[0], modalBodyElt.firstChild);
                            //$alerts = $alerts.add($elt);
                        //});
                    //}
                //});
            }, 3000);

            eventMgr.addListener('onOfflineChanged', checkPayment);

            // Other initialization that are not prioritary
            eventMgr.addListener("onReady", function() {

                $('.modal').on('shown.bs.modal', function() {
                    var $elt = $(this);
                    setTimeout(function() {
                        // When modal opens focus on the first button
                        $elt.find('.btn:first').focus();
                        // Or on the first link if any
                        $elt.find('button:first').focus();
                        // Or on the first input if any
                        $elt.find("input:enabled:visible:first").focus();
                    }, 50);
                }).on('hidden.bs.modal', function() {
                    // Focus on the editor when modal is gone
                    editor.focus();
                    // Revert to current theme when settings modal is closed
                    applyTheme(window.theme);
                }).keyup(function(e) {
                    // Handle enter key in modals
                    if(e.which == 13 && !$(e.target).is("textarea")) {
                        $(this).find(".modal-footer a:last").click();
                    }
                });

                // Click events on "insert link" and "insert image" dialog buttons
                $(".action-insert-link").click(function(e) {
                    var value = utils.getInputTextValue($("#input-insert-link"), e);
                    if(value !== undefined) {
                        core.insertLinkCallback(value);
                        core.insertLinkCallback = undefined;
                    }
                });
                $(".action-insert-image").click(function(e) {
                    var value = utils.getInputTextValue($("#input-insert-image"), e);
                    if(value !== undefined) {
                        core.insertLinkCallback(value);
                        core.insertLinkCallback = undefined;
                    }
                });

                // Hide events on "insert link" and "insert image" dialogs
                $(".modal-insert-link, .modal-insert-image").on('hidden.bs.modal', function() {
                    if(core.insertLinkCallback !== undefined) {
                        core.insertLinkCallback(null);
                        core.insertLinkCallback = undefined;
                    }
                });

                // Settings loading/saving
                $(".action-load-settings").click(function() {
                    loadSettings();
                });
                $(".action-apply-settings").click(function(e) {
                    saveSettings(e);
                    if(!e.isPropagationStopped()) {
                        window.location.reload();
                    }
                });
                $('.action-add-google-drive-account').click(function() {
                    if(settings.gdriveMultiAccount === 3) {
                        return;
                    }
                    settings.gdriveMultiAccount++;
                    storage.settings = JSON.stringify(settings);
                    window.location.reload();
                });

                // Hot theme switcher in the settings
                var currentTheme = window.theme;

                function applyTheme(theme) {
                    theme = theme || 'default';
                    if(currentTheme != theme) {
                        var themeModule = "less!themes/" + theme;
                        if(window.baseDir.indexOf('-min') !== -1) {
                            themeModule = "css!themes/" + theme;
                        }
                        // Undefine the module in RequireJS
                        requirejs.undef(themeModule);
                        // Then reload the style
                        require([
                                themeModule
                                ]);
                        currentTheme = theme;
                    }
                }

                $themeInputElt = $("#input-settings-theme");
                $themeInputElt.on("change", function() {
                    applyTheme(this.value);
                });

                // Import docs and settings
                $(".action-import-docs-settings").click(function() {
                    $("#input-file-import-docs-settings").click();
                });
                var newstorage;
                $("#input-file-import-docs-settings").change(function(evt) {
                    var files = (evt.dataTransfer || evt.target).files;
                    $(".modal-settings").modal("hide");
                    _.each(files, function(file) {
                        var reader = new FileReader();
                        reader.onload = (function(importedFile) {
                            return function(e) {
                                try {
                                    newstorage = JSON.parse(e.target.result);
                                    // Compare storage version
                                    var newVersion = parseInt(newstorage.version.match(/^v(\d+)$/)[1], 10);
                                    var currentVersion = parseInt(storage.version.match(/^v(\d+)$/)[1], 10);
                                    if(newVersion > currentVersion) {
                                        // We manage storage upgrade, not downgrade
                                        eventMgr.onError("Incompatible version. Please upgrade StackEdit.");
                                    } else {
                                        $('.modal-import-docs-settings').modal('show');
                                    }
                                }
                                catch(exc) {
                                    eventMgr.onError("Wrong format: " + importedFile.name);
                                }
                                $("#input-file-import-docs-settings").val('');
                            };
                        })(file);
                        reader.readAsText(file);
                    });
                });
                $(".action-import-docs-settings-confirm").click(function() {
                    storage.clear();
                    var allowedKeys = /^file\.|^folder\.|^publish\.|^settings$|^sync\.|^google\.|^author\.|^themeV4$|^version$/;
                    _.each(newstorage, function(value, key) {
                        if(allowedKeys.test(key)) {
                            storage[key] = value;
                        }
                    });
                    window.location.reload();
                });
                // Export settings
                $(".action-export-docs-settings").click(function() {
                    utils.saveAs(JSON.stringify(storage), "StackEdit local storage.json");
                });

                $(".action-default-settings").click(function() {
                    storage.removeItem("settings");
                    storage.removeItem("theme");
                    if(!settings.dropboxFullAccess) {
                        storage.removeItem('dropbox.lastChangeId');
                    }
                    window.location.reload();
                });

                $(".action-app-reset").click(function() {
                    storage.clear();
                    window.location.reload();
                });

                // Reset inputs
                $(".action-reset-input").click(function() {
                    utils.resetModalInputs();
                });

                utils.createTooltip(".tooltip-lazy-rendering", 'Disable preview rendering while typing in order to offload CPU. Refresh preview after 500 ms of inactivity.');
                utils.createTooltip(".tooltip-default-content", [
                        'Thanks for supporting StackEdit by adding a backlink in your documents!<br/><br/>',
                        '<b class="text-danger">NOTE: Backlinks in Stack Exchange Q/A are not welcome.</b>'
                        ].join(''));
                utils.createTooltip(".tooltip-template", settingsTemplateTooltipHTML);
                utils.createTooltip(".tooltip-pdf-options", settingsPdfOptionsTooltipHTML);

                // Avoid dropdown panels to close on click
                $("div.dropdown-menu").click(function(e) {
                    e.stopPropagation();
                });

                // Non unique window dialog
                $('.modal-non-unique').modal({
                    backdrop: "static",
                    keyboard: false,
                    show: false
                });

                // Load images
                _.each(document.querySelectorAll('img'), function(imgElt) {
                    var $imgElt = $(imgElt);
                    var src = $imgElt.data('stackeditSrc');
                    if(src) {
                        $imgElt.attr('src', window.baseDir + '/img/' + src);
                    }
                });

                if(window.viewerMode === false) {
                    // Load theme list
                    var themeOptions = _.reduce(constants.THEME_LIST, function(themeOptions, name, value) {
                        return themeOptions + '<option value="' + value + '">' + name + '</option>';
                    }, '');
                    document.getElementById('input-settings-theme').innerHTML = themeOptions;
                }

                //$('.modal-header').append('<a class="dialog-header-message" href="https://github.com/benweet/stackedit/issues/385" target="_blank">Give your feedback <i class="icon-megaphone"></i></a>');
                checkPayment();
            });

            return core;
        });
